home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / misc / volume4 / lmail < prev    next >
Encoding:
Text File  |  1989-02-03  |  18.0 KB  |  680 lines

  1. Path: xanth!nic.MR.NET!hal!ncoast!allbery
  2. From: zeeff@b-tech.ann-arbor.mi.us.UUCP (Jon Zeeff)
  3. Newsgroups: comp.sources.misc
  4. Subject: v04i130: lmail, a local mail delivery program
  5. Keywords: lmail, smail
  6. Message-ID: <4875@b-tech.ann-arbor.mi.us>
  7. Date: 22 Oct 88 01:22:17 GMT
  8. Sender: allbery@ncoast.UUCP
  9. Reply-To: zeeff@b-tech.ann-arbor.mi.us.UUCP (Jon Zeeff)
  10. Organization: Branch Technology, Ann Arbor, MI
  11. Lines: 666
  12. Approved: allbery@ncoast.UUCP
  13.  
  14. Posting-number: Volume 4, Issue 130
  15. Submitted-by: "Jon Zeeff" <zeeff@b-tech.ann-arbor.mi.us.UUCP>
  16. Archive-name: lmail
  17.  
  18. Too many people are requesting this so I guess it should go to
  19. comp.sources.misc.
  20.  
  21. This program is a local mail delivery agent.  It's primary use is to
  22. add piping to files and programs for sites running smail2.5.  Make sure that
  23. it does locking the way you want it to.
  24.  
  25. #! /bin/sh
  26. # This is a shell archive.  Remove anything before this line, then unpack
  27. # it by saving it into a file and typing "sh file".  To overwrite existing
  28. # files, type "sh file -c".  You can also feed this as standard input via
  29. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  30. # will see the following message at the end:
  31. #        "End of shell archive."
  32. # Contents:  lmail.c
  33. # Wrapped by zeeff@b-tech on Mon Oct 17 10:26:40 1988
  34. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  35. if test -f lmail.c -a "${1}" != "-c" ; then 
  36.   echo shar: Will not over-write existing file \"lmail.c\"
  37. else
  38. echo shar: Extracting \"lmail.c\" \(15989 characters\)
  39. sed "s/^X//" >lmail.c <<'END_OF_lmail.c'
  40. X/* #ident "@(#)lmail.c    1.1.1.1    88/09/09 15:07:52 " */
  41. X/*
  42. X *    lmail replacement  V 2.7 
  43. X *
  44. X * Copyright 1988 Jon Zeeff    (umix!b-tech!zeeff)
  45. X * Updated by "Greg A. Woods" <umix!ixpierre!woods>
  46. X *
  47. X * Permission is granted to use this in any manner provided that    
  48. X * 1) the copyright notice is left intact, 2) you don't hold me 
  49. X * responsible for any bugs and 3) you mail me any improvements that you 
  50. X * make.  
  51. X * 
  52. X * This program can be used with smail as the local delivery agent (lmail).
  53. X * It's primary benefit is that it allows forwarding to programs and files.
  54. X * It also allows undeliverable local mail to be saved.
  55. X * 
  56. X * Caution: I wrote this for my own use and it does what I want.  I    
  57. X * haven't looked into all portability and security issues nor is the 
  58. X * code as clean as I would like.  Use at your own risk.  
  59. X * 
  60. X * Note that a .fwd file in /usr/spool/uucppublic is ignored since    
  61. X * it is usually publically writable.  If you have other publically 
  62. X * writable home directories, you need to change this program to also 
  63. X * exclude these other directories.  
  64. X * 
  65. X * This program should be:
  66. X * 
  67. X *    -rws--x--x   1 root     mail       19030 Sep 14 12:11 /bin/lmail
  68. X * 
  69. X * You need to create an empty file /usr/mail/.lock
  70. X * and lmail-aliases.  Aliases should contain the name
  71. X * you want aliased followed by new name(s).  Eg.
  72. X * 
  73. X *    postmaster sam "|/usr/postmaster/postsaver -c"
  74. X * 
  75. X * will cause mail to postmaster to go to sam and be piped into  the 
  76. X * program postsaver with the -c option.  Both will be done while suid 
  77. X * MAILMAN.
  78. X * 
  79. X * Users can also forward mail with a .fwd file in their home    
  80. X * directory.  This contains just new names.  References to files and 
  81. X * programs in user's .fwd file will be executed suid that user.  
  82. X * This is a security hole if the directory is writable by others!
  83. X * Also be careful with .fwd files where several ids share a home
  84. X * directory.
  85. X * 
  86. X * This program was written for a Sys V.2 or V.3 system running smail 2.5.
  87. X * 
  88. X * Step by step installation:
  89. X * 
  90. X * 1) Change MAILGID define if mail is not group 6.
  91. X * 2) Add mailman to /etc/passwd with no special uid or group.
  92. X * 3) Compile with 'cc lmail.c -s -O -o lmail'
  93. X * 4) Create empty files lmail-aliases and /usr/mail/.lock
  94. X *    These should be rw group mail.
  95. X * 
  96. X * 5) Install as /bin/lmail with suid root perms.
  97. X * 6) Test 
  98. X */
  99. X
  100. X#include <stdio.h>
  101. X#include <limits.h>
  102. X#include <sys/types.h>
  103. X#include <pwd.h>
  104. X#include <grp.h>
  105. X#include <utmp.h>
  106. X#include <signal.h>
  107. X#include <ctype.h>
  108. X#include <time.h>
  109. X#include <sys/stat.h>
  110. X#include <setjmp.h>
  111. X#include <sys/utsname.h>
  112. X#include <string.h>
  113. X
  114. Xvoid        exit();
  115. Xvoid        _exit();
  116. Xunsigned int    sleep();
  117. Xtime_t        time();
  118. X
  119. X/*
  120. X *    Change these defines to fit your needs
  121. X */
  122. X#define MAX_LINE    512            /* input line buffer size */
  123. X#define DEF_PATH    "PATH=/bin:/usr/bin:/usr/lbin"
  124. X#define MAIL_TMPFILE    "/tmp/rmXXXXXX"
  125. X#define ROOT        "root"
  126. X#define DEF_IFS        "IFS= \t\n"
  127. X#define DEF_SHELL    "SHELL=/bin/sh"
  128. X#define FROM_LINE    "From "
  129. X#define FROM_FMT    "From %s %24.24s\n"
  130. X#define FROM_PREFX    '>'
  131. X#define REMOTE_FROM    " remote from "
  132. X#define ALIAS_FILE    "/usr/local/lib/lmail-aliases"
  133. X#define MAIL_DIR    "/usr/mail/"
  134. X#define LOCK_SUFF    ".lock"
  135. X#define LOCK_FILE    "/usr/mail/.lock"
  136. X#define FWD_LINE    "Forward to "
  137. X#define FWD_FILE    "/.fwd"
  138. X#define PUBDIR_FWD    "/usr/spool/uucppublic/.fwd"
  139. X#define REMOTE_MAILER    "/bin/rmail %s"     /* %s will be replace by address */
  140. X#ifndef PATH_MAX
  141. X#define PATH_MAX    1024
  142. X#endif
  143. X
  144. X
  145. X
  146. X/*
  147. X * GID of mail for creating mail files in /usr/mail. It's faster to just type
  148. X * it in here, and it probably won't change anyway (we hope).
  149. X */
  150. X#define MAILGID        6
  151. X
  152. X/*
  153. X * MAILMAN should be a user id with no special permissions or files.  Make
  154. X * sure you add a /etc/passwd entry for it, 'cause I'm going to check.
  155. X */
  156. X#define MAILMAN        "mailman"    /* "mailman" */
  157. X
  158. X/*
  159. X * BADMAIL is a name to send a copy of bad mail to.  Can be left undefined.
  160. X */
  161. X#define BADMAIL        "/usr/mail/badmail"    /* "/usr/mail/badmail" */
  162. X
  163. X/*
  164. X * Maximum size of aliasing table (NOTE: this uses a lot of space!)
  165. X */
  166. X#define MAX_ADDR    50
  167. X
  168. Xstruct {
  169. X    char    dest[MAX_LINE];        /* to whom it should go */
  170. X    char    source[MAX_LINE];    /* who it is from */
  171. X    char    user[MAX_LINE];     /* user to suid to for '|' and files */
  172. X} table[MAX_ADDR];
  173. X
  174. Xchar        *thissys;        /* This system's name */
  175. XFILE        *mailfile;        /* FILE pointer for mailbox */
  176. Xint        num_addresses;
  177. Xlong        iop;
  178. Xstruct utsname    utsn;
  179. Xstruct passwd    *pwd;
  180. Xstruct passwd    *pwd_mailman;
  181. X
  182. Xstruct passwd    *getpwnam();
  183. XFILE        *fopen();
  184. Xunsigned short    getuid();
  185. Xchar        *mktemp();
  186. XFILE        *popen();
  187. X
  188. Xvoid        alias();
  189. Xvoid        copy();
  190. Xvoid        lock();
  191. Xvoid        unlock();
  192. X
  193. X/* ARGSUSED */
  194. Xint
  195. Xmain(argc, argv, envp)
  196. X    int    argc;
  197. X    char    *argv[];
  198. X    char    *envp[];
  199. X{
  200. X    char    *address;
  201. X    char    from[MAX_LINE];        /* Original author */
  202. X    char    line[MAX_LINE];
  203. X    int    i;
  204. X    int    error_flag = 0;
  205. X    char    *ptr;
  206. X
  207. X    static char    tempfname[] = MAIL_TMPFILE;
  208. X
  209. X    if (argc < 2)
  210. X        exit(1);    /* return error if not at least 1 address */
  211. X    umask(006);        /* mail files MUST be group write-able */
  212. X    uname(&utsn);
  213. X    /*
  214. X     * If being fed from a pipe, copy to a temp file so we can rewind
  215. X     */
  216. X    if (fseek(stdin, 0L, 0) != 0) {
  217. X        mailfile = fopen(mktemp(tempfname), "w+");
  218. X        unlink(tempfname);        /* it'll be gone when we are */
  219. X        if (mailfile == NULL) {
  220. X            (void) fprintf(stderr, "Can't create temp file - no mail delivered\n");
  221. X            exit(3);
  222. X        }
  223. X        while (fgets(line, MAX_LINE, stdin) != NULL) {
  224. X            if (fputs(line, mailfile) == EOF) {
  225. X                (void) fprintf(stderr, "Can't write temp file - no mail delivered\n");
  226. X                exit(3);
  227. X            }
  228. X        }
  229. X        rewind(mailfile);
  230. X    } else
  231. X        mailfile = stdin;
  232. X    thissys = utsn.nodename;
  233. X    if ((pwd_mailman = getpwnam(MAILMAN)) == NULL) {
  234. X        (void) fprintf(stderr, "*** Error - can't find mailman uid\n");
  235. X        exit(7);
  236. X    }
  237. X    time(&iop);
  238. X    putenv(DEF_PATH);
  239. X    putenv(DEF_IFS);
  240. X    putenv(DEF_SHELL);
  241. X    /*
  242. X     * Get the From_ line for the author - assume smail has folded it
  243. X     */
  244. X    from[0] = '\0';
  245. X    fgets(line, MAX_LINE, mailfile);
  246. X    rewind(mailfile);
  247. X    if (strncmp(line, FROM_LINE, sizeof(FROM_LINE) - 1) != 0) {
  248. X        (void) fprintf(stderr, "*** Error - mail is in incorrect format\n");
  249. X        exit(2);
  250. X    }
  251. X    /*
  252. X     * If remote from exists, then include that site name in address so that
  253. X     * there is no remote from on the end
  254. X     */
  255. X    ptr = strrchr(line, ' ') - 1;
  256. X    while (*ptr != ' ')
  257. X        --ptr;
  258. X    --ptr;
  259. X    while (*ptr != ' ')
  260. X        --ptr;
  261. X    if (strncmp(ptr, REMOTE_FROM, sizeof(REMOTE_FROM) - 1) == 0) {
  262. X        (void) strcat(from, strrchr(line, ' ') + 1);
  263. X        *(strrchr(from, '\n')) = '!';
  264. X    }
  265. X    (void) strcat(from, strchr(line, ' ') + 1);
  266. X    *(strchr(from, ' ')) = '\0';
  267. X    /*
  268. X     * Put the first entrys into the aliasing table
  269. X     */
  270. X    --argc;
  271. X    for (num_addresses = 0; num_addresses < argc; ++num_addresses) {
  272. X        address = argv[num_addresses+1];
  273. X        if (ptr = strchr(address, ' '))
  274. X            *ptr = '\0';    /* Remove trailing spaces */
  275. X        /*
  276. X         * Mailing to file or program is illegal at this point We
  277. X         * can't have outsiders mailing directly to files
  278. X         */
  279. X        if (address[0] == '/' || address[0] == '|')
  280. X            exit(1);
  281. X        (void) strcpy(table[num_addresses].dest, address);
  282. X        (void) strcpy(table[num_addresses].source, from);
  283. X        (void) strcpy(table[num_addresses].user, MAILMAN);
  284. X    }
  285. X    alias();            /* expand address recursively */
  286. X    signal(SIGHUP, SIG_IGN);
  287. X    signal(SIGINT, SIG_IGN);
  288. X    signal(SIGQUIT, SIG_IGN);
  289. X    /*
  290. X     * Now deliver them
  291. X     */
  292. X    for (i = 0; i < num_addresses; i++) {
  293. X        if (*(table[i].source) != '\0')    /* if not deleted */
  294. X            error_flag |= deliver(mailfile, from, table[i].dest, table[i].user);
  295. X    }
  296. X#ifdef BADMAIL
  297. X    if (error_flag)
  298. X        deliver(mailfile, from, BADMAIL, ROOT);
  299. X#endif
  300. X    /*
  301. X     * Realize here that if there is any kind of error, smail will return
  302. X     * mail to the author.  Even if the error was on the part of some
  303. X     * local user who did an alias wrong.
  304. X     */
  305. X    return(error_flag);
  306. X}
  307. X
  308. X
  309. X/*
  310. X * This routine recursively aliases an address creating a table of addresses.
  311. X */
  312. Xvoid
  313. Xalias()
  314. X{
  315. X    FILE        *in_file;
  316. X    int        i;
  317. X    int        j;
  318. X    char        *p;
  319. X    char        *p2;
  320. X    char        owner[MAX_LINE];
  321. X    char        file[PATH_MAX];
  322. X    char        line[MAX_LINE];
  323. X    FILE        *aliases;
  324. X    struct stat    statbuf;
  325. X
  326. X    if ((aliases = fopen(ALIAS_FILE, "r")) == (FILE *) NULL)
  327. X        return;
  328. X    /*
  329. X     * Make sure someone didn't break mail and link some file to aliases.
  330. X     * Sys V doesn't have sym links, so we don't worry about that.
  331. X     */
  332. X    fstat(fileno(aliases), &statbuf);
  333. X    if (statbuf.st_nlink > 1) {
  334. X        fclose(aliases);
  335. X        return; 
  336. X    }
  337. X    for (i = 0; i < num_addresses; ++i) {
  338. X        /*
  339. X         * Only alias it if it has never been seen before
  340. X         */
  341. X        for (j = 0; j < i; ++j) {
  342. X            if (strcmp(table[j].dest, table[i].dest) == 0)
  343. X                break;
  344. X        }
  345. X        if (j < i)
  346. X            continue;
  347. X        /*
  348. X         * find a matching line in aliases
  349. X         */
  350. X        rewind(aliases);
  351. X        while (fscanf(aliases, "%s %s", file, line) > 0) {
  352. X            if (strcmp(file, table[i].dest) == 0)
  353. X                break;
  354. X        }
  355. X        if (!feof(aliases)) {         /* we found one in aliases */
  356. X            p = line;
  357. X            (void) strcpy(owner, MAILMAN);
  358. X        } else {
  359. X            /*
  360. X             * try the users .fwd file.  This is preferred over
  361. X             * Forward to lines
  362. X             */
  363. X            if ((pwd = getpwnam(table[i].dest)) == NULL)
  364. X                continue;
  365. X            (void) strcpy(file, pwd->pw_dir);
  366. X            (void) strcat(file, FWD_FILE);
  367. X            /*
  368. X             * /usr/spool/uucppublic is normally a publically
  369. X             * writable home directory.  Ignore any .fwd there.
  370. X             */
  371. X            if (strcmp(file, PUBDIR_FWD) != 0 && (in_file = fopen(file, "r")) != NULL) {
  372. X                /*
  373. X                 * ignore it if there is anything funny going
  374. X                 * on with links
  375. X                 */
  376. X                fstat(fileno(in_file), &statbuf);
  377. X                if (statbuf.st_nlink > 1 || fgets(line, MAX_LINE, in_file) == NULL) {
  378. X                    fclose(in_file);
  379. X                    continue;
  380. X                }
  381. X                fclose(in_file);
  382. X                p = line;
  383. X                (void) strcpy(owner, table[i].dest);
  384. X            } else {
  385. X                /*
  386. X                 * maybe they have a Forward to in their mail
  387. X                 * file
  388. X                 */
  389. X                (void) strcpy(file, MAIL_DIR);
  390. X                (void) strcat(file, table[i].dest);
  391. X                if ((in_file = fopen(file, "r")) == (FILE *) NULL)
  392. X                    continue;
  393. X                /*
  394. X                 * ignore it if there is anything funny going
  395. X                 * on with links
  396. X                 */
  397. X                fstat(fileno(in_file), &statbuf);
  398. X                if (statbuf.st_nlink > 1 || fgets(line, MAX_LINE, in_file) == (char *) NULL) {
  399. X                    fclose(in_file);
  400. X                    continue;
  401. X                }
  402. X                fclose(in_file);
  403. X                if (strncmp(line, FWD_LINE, sizeof(FWD_LINE) - 1) != 0) continue;
  404. X                p = line + 11;
  405. X                /*
  406. X                 * we only allow simple forwards with this
  407. X                 * method this is overly simple
  408. X                 */
  409. X                if (strchr(p, '/') || strchr(p, '|'))
  410. X                    continue;
  411. X                (void) strcpy(owner, MAILMAN);
  412. X            }
  413. X        }
  414. X        /*
  415. X         * p now points to a line of addresses.  Mark the current
  416. X         * entry as deleted since it was just aliased.
  417. X         */
  418. X        *(table[i].source) = '\0';
  419. X        while (*p > '\n') {
  420. X            if (*p == '"') { 
  421. X                p2 = p + 1;
  422. X                while (*(++p) && *p != '"')
  423. X                    ;    /* NO_OP */
  424. X            } else {
  425. X                p2 = p;
  426. X                while (*p > ' ')
  427. X                    ++p;
  428. X            }
  429. X            if (*p != '\0')
  430. X                *(p++) = '\0';
  431. X            /*
  432. X             * Is an unaliased version of this already in the
  433. X             * table?
  434. X             */
  435. X            for (j = 0; j < num_addresses; ++j) {
  436. X                if (strcmp(table[j].dest, p2) == 0 && *(table[j].source) != '\0')
  437. X                    break;
  438. X            }
  439. X            /*
  440. X             * Add new entry if it finished the above loop
  441. X             */
  442. X            if (j == num_addresses) {
  443. X                (void) strcpy(table[num_addresses].dest, p2);
  444. X                (void) strcpy(table[num_addresses].source, table[i].dest);
  445. X                (void) strcpy(table[num_addresses].user, owner);
  446. X                if (++num_addresses >= MAX_ADDR) { 
  447. X                    --num_addresses;
  448. X                    return;
  449. X                }
  450. X            }
  451. X            /*
  452. X             * Move past spaces
  453. X             */
  454. X            while (*p == ' ')
  455. X                ++p;
  456. X        }
  457. X    }
  458. X    fclose(aliases);
  459. X    return;
  460. X}
  461. X
  462. X/*
  463. X * This routine attempts to deliver the mail
  464. X */
  465. Xint
  466. Xdeliver(in_fd, author, dest_ptr, user)
  467. X    FILE    *in_fd;        /* Input file */
  468. X    char    *author;    /* Who message is from (with address) */
  469. X    char    *dest_ptr;    /* Who message is to */
  470. X    char    *user;        /* User responsible for this to address */
  471. X{
  472. X    char    dest[MAX_LINE];
  473. X    char    temp[MAX_LINE];
  474. X    FILE    *outfile;
  475. X    int    pid;
  476. X    int    w;
  477. X    int    status;
  478. X
  479. X    rewind(in_fd);
  480. X    (void) strcpy(dest, dest_ptr);
  481. X    if ((strchr(dest, '!') || strchr(dest, '@') || strchr(dest, '%')) && dest[0] != '|' && dest[0] != '/') {    /* A remote address */
  482. X        /*
  483. X         * fix things that have only a %
  484. X         */
  485. X        if (strchr(dest, '!') == (char *) NULL && strchr(dest, '@') == (char *) NULL) 
  486. X            *(strchr(dest, '%')) = '@';
  487. X        sprintf(temp, REMOTE_MAILER, dest);
  488. X        if ((pwd = getpwnam(user)) == (struct passwd *) NULL)
  489. X            pwd = pwd_mailman;
  490. X        if (pid = fork()) {
  491. X            while ((w = wait(&status)) != pid && w != -1)
  492. X                ;    /* NO_OP */
  493. X            if (status || w == -1) {
  494. X                (void) fprintf(stderr, "\nCannot run %s\n", temp);
  495. X                return(8);
  496. X            }
  497. X        } else {
  498. X            setgid(pwd->pw_gid);
  499. X            setuid(pwd->pw_uid);
  500. X            umask(066);
  501. X            if ((outfile = popen(temp, "w")) == (FILE *) NULL)
  502. X                _exit(1);
  503. X            copy(outfile, in_fd, author);
  504. X            if (pclose(outfile))
  505. X                _exit(1);
  506. X            _exit(0);
  507. X        }
  508. X    } else {
  509. X        if (dest[0] == '|') {
  510. X            if ((pwd = getpwnam(user)) == (struct passwd *) NULL)
  511. X                pwd = pwd_mailman;
  512. X            if (pid = fork()) {
  513. X                while ((w = wait(&status)) != pid && w != -1)
  514. X                    ;
  515. X                if (status || w == -1) {
  516. X                    (void) fprintf(stderr, "\nCannot pipe to program %s\n", dest);
  517. X                    return(8);
  518. X                }
  519. X            } else {
  520. X                setgid(pwd->pw_gid);
  521. X                setuid(pwd->pw_uid);
  522. X                umask(066);
  523. X                if ((outfile = popen(dest + 1, "w")) == (FILE *) NULL)
  524. X                    _exit(1);
  525. X                copy(outfile, in_fd, author);
  526. X                if (pclose(outfile))
  527. X                    _exit(1);
  528. X                _exit(0);
  529. X            }
  530. X        } else { 
  531. X            if (dest[0] == '/') {
  532. X                if ((pwd = getpwnam(user)) == (struct passwd *) NULL)
  533. X                    pwd = pwd_mailman;
  534. X                if (pid = fork()) {
  535. X                    while ((w = wait(&status)) != pid && w != -1)
  536. X                        ;    /* NO_OP */
  537. X                    if (status || w == -1) {
  538. X                        (void) fprintf(stderr, "\nCannot save in file %s\n", dest);
  539. X                        return(8);
  540. X                    }
  541. X                } else {
  542. X                    setgid(pwd->pw_gid);
  543. X                    setuid(pwd->pw_uid);
  544. X                    umask(066);
  545. X                    lock2(dest);
  546. X                    if ((outfile = fopen(dest, "a")) == (FILE *) NULL)
  547. X                        _exit(1);
  548. X                    copy(outfile, in_fd, author);
  549. X                    fclose(outfile);
  550. X                    unlock(dest);
  551. X                    _exit(0);
  552. X                }
  553. X            } else {        /* a local user address */
  554. X                /*
  555. X                 * Check if this is a valid user
  556. X                 */
  557. X                if ((pwd = getpwnam(dest)) == NULL) {
  558. X                    (void) fprintf(stderr, "User %s does not exist\n", dest);
  559. X                    return(4);
  560. X                }
  561. X                if (pid = fork()) {
  562. X                    while ((w = wait(&status)) != pid && w != -1)
  563. X                        ;
  564. X                    if (status || w == -1) {
  565. X                        (void) fprintf(stderr, "\nCannot save in file %s\n", dest);
  566. X                        return(8);
  567. X                    }
  568. X                } else {
  569. X                    setgid(MAILGID);
  570. X                    setuid(pwd_mailman->pw_uid);    /* give up root uid */
  571. X                    sprintf(temp, "%s%s", MAIL_DIR, dest);
  572. X                    lock(temp);
  573. X                    status = 0;
  574. X                    if ((outfile = fopen(temp, "a")) == NULL) {
  575. X                        (void) fprintf(stderr, "** Can't open user mail file %s\n", temp);
  576. X                        status = 5;
  577. X                    } else
  578. X                        copy(outfile, in_fd, author);
  579. X                    chown(temp, (int)pwd->pw_uid, MAILGID);
  580. X                    if (fclose(outfile)) {
  581. X                        (void) fprintf(stderr, "** Could not close mail file %s\n", temp);
  582. X                        status = 7;
  583. X                    }
  584. X                    unlock(temp);
  585. X                    _exit(status);
  586. X                }
  587. X            }
  588. X        }
  589. X    }
  590. X    return(0);
  591. X}
  592. X
  593. Xvoid
  594. Xcopy(out, in, from)
  595. X    FILE    *out;
  596. X    FILE    *in;
  597. X    char    *from;
  598. X{
  599. X    char    temp[MAX_LINE];
  600. X
  601. X    /*
  602. X     * Throw away From_ line and replace with our own
  603. X     */
  604. X    fgets(temp, MAX_LINE, in);
  605. X    (void) fprintf(out, FROM_FMT, from, ctime(&iop));
  606. X    while (fgets(temp, MAX_LINE, in) != NULL) {
  607. X        if (strncmp(temp, FROM_LINE, sizeof(FROM_LINE) - 1) == 0)
  608. X            (void) fputc(FROM_PREFX, out); 
  609. X        (void) fputs(temp, out);
  610. X    }
  611. X    (void) fputc('\n', out);
  612. X    return;
  613. X}
  614. X
  615. X/*
  616. X * This routine works while uid = root
  617. X */
  618. Xvoid
  619. Xlock(file)
  620. X    char    *file;
  621. X{
  622. X    char    lockfile[PATH_MAX];
  623. X    int    i;
  624. X
  625. X    (void) strcpy(lockfile, file);
  626. X    (void) strcat(lockfile, LOCK_SUFF);
  627. X    for (i = 0; i < 100; i++) {
  628. X        if (link(LOCK_FILE, lockfile) == 0)
  629. X            return;
  630. X        sleep(5);
  631. X    }    
  632. X    return;
  633. X}
  634. X
  635. X/*
  636. X * This routine is used for files in user's directories
  637. X */
  638. Xlock2(file)
  639. X    char    *file;
  640. X{
  641. X    char    lockfile[PATH_MAX];
  642. X    int    f;
  643. X    int    i;
  644. X
  645. X    (void) strcpy(lockfile, file);
  646. X    (void) strcat(lockfile, LOCK_SUFF);
  647. X    for (i = 0; i < 100; i++) {
  648. X        if ((f = creat(lockfile, 0)) >= 0) {
  649. X            close(f);
  650. X            return;
  651. X        } else
  652. X            sleep(5);
  653. X    }    
  654. X}
  655. X
  656. Xvoid
  657. Xunlock(file)
  658. X    char    *file;
  659. X{
  660. X    char    lockfile[PATH_MAX];
  661. X
  662. X    (void) strcpy(lockfile, file);
  663. X    (void) strcat(lockfile, LOCK_SUFF);
  664. X    (void) unlink(lockfile);
  665. X    return;
  666. X}
  667. X
  668. X
  669. END_OF_lmail.c
  670. if test 15989 -ne `wc -c <lmail.c`; then
  671.     echo shar: \"lmail.c\" unpacked with wrong size!
  672. fi
  673. # end of overwriting check
  674. fi
  675. echo shar: End of shell archive.
  676. exit 0
  677. -- 
  678. Jon Zeeff                  Branch Technology,
  679. umix!b-tech!zeeff          zeeff@b-tech.ann-arbor.mi.us
  680.